package com.apimarket.service;

import com.apimarket.dao.ApiInterfaceMapper;
import com.apimarket.dao.RoutePathsMapper;
import com.apimarket.entity.ApiInterfaceWithBLOBs;
import com.apimarket.entity.ApiSet;
import com.apimarket.entity.kong.Route;
import com.apimarket.enums.ExceptionEnum;
import com.apimarket.enums.KongNameEnum;
import com.apimarket.exception.AMException;
import com.apimarket.exception.KongNameException;
import com.apimarket.util.RedisUtils;
import com.apimarket.util.kong.KongOperationType;
import com.apimarket.util.kong.KongRoute;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.net.URISyntaxException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @Description:
 * @Author ZXR
 * @Date 2021/7/2 18:34
 * @Version 1.0
 */

@Service
public class RouteService {
    //用父类来接收和他的代理模式有关
    @Autowired
    private KongRoute kongRoute;
    @Autowired
    private ApiInterfaceMapper apiInterfaceMapper;
    @Autowired
    RedisUtils redisUtils;
    @Value("${redis.route.key}")
    private String routeRedisKey;
    @Value("${spring.kong.net}")
    private String kongNet;
    @Autowired
    private RoutePathsMapper routePathsMapper;

    //这里的Transactional还不能生效
    //@Transactional(rollbackFor = {Exception.class})
    public void deleteRouteById(String id) throws IOException, URISyntaxException {
        //看这个Route底下的api接口有几个
        int count=apiInterfaceMapper.getRouteChildAPINum(id);
        if(count>0){
            throw new AMException(ExceptionEnum.Del_ROUTE_HAS_API);
        }
        kongRoute.deleteRoute(id);
        //把这个route下的所有接口都删除
        //apiInterfaceMapper.deleteByRouteId(id);
    }

    public PageInfo<ApiInterfaceWithBLOBs> getPageChildInterface(String id, String name, Integer pageSize, Integer pageCurrent) {
        // 1.参数校验
        if(pageCurrent==null||pageCurrent<1)
            throw new IllegalArgumentException("当前页码有误");
        if(pageSize==null||pageSize<1)
            throw new IllegalArgumentException("当前页显示数目有误");
        PageHelper.startPage(pageCurrent,pageSize);
        List<ApiInterfaceWithBLOBs> list=apiInterfaceMapper.selectByOrderId(id,name);
        if(list.size()==0)
            throw new AMException(ExceptionEnum.Interface_NOT_FOUND);
        //丢给pageInfo处理，拿到总条数，页数，页码等等
        PageInfo<ApiInterfaceWithBLOBs> pageInfo=new PageInfo<>(list);
        return pageInfo;
    }

    //@Transactional(rollbackFor = {Exception.class})
    public void updateRouteById(Route route) throws IOException, URISyntaxException {
        if(StringUtils.isEmpty(route.getId())){
            throw new IllegalArgumentException("route的id不能为null");
        }
       /* Route newRoute=new Route();
        newRoute.setId(route.getId());
        newRoute.setName(route.getName());
        newRoute.setPaths(route.getPaths());
        newRoute.setService(route.getService());
        List<String> methods = route.getMethods();*/
        if(!route.getMethods().contains("OPTIONS"))
            route.getMethods().add("OPTIONS");
        //newRoute.setMethods(methods);
        //kongRoute.updateRoute(newRoute);
        kongRoute.updateRouteAndJudege(route, KongOperationType.ROUTE_UPDATE);
        //需要从缓存中把route信息给删除
        redisUtils.judgeAndRemove(routeRedisKey);

        //然后需要修改业务数据库
        //拿到属于这个route的所有接口的id
        List<String> paths=route.getPaths();
        List<ApiInterfaceWithBLOBs> apiInterfaceWithBLOBs = apiInterfaceMapper.selectByOrderId(route.getId(), "");
        //用一个集合存放需要被修改的接口集
        if(apiInterfaceWithBLOBs.size()!=0){
            List<ApiInterfaceWithBLOBs> needUpdate=new ArrayList<>();
            for(ApiInterfaceWithBLOBs temp:apiInterfaceWithBLOBs){
                HashMap<String,String> map=getPath(temp.getUrl());
                String tempPath=map.get("path");
                String controllerUrl=map.get("controllerUrl");
                if(!paths.contains(tempPath)){
                    //如果原来的path和修改后的path不一样，那么这个接口就需要修改
                    temp.setUrl(updateUrl(paths,controllerUrl));
                    needUpdate.add(temp);
                }
            }
            //然后需要批量更新接口数据
            if(needUpdate.size()>0)
                apiInterfaceMapper.updateListById(needUpdate);
        }
    }
    //拼接url
    public String updateUrl(List<String> paths,String controllerUrl){
        //需要将url处理成http://kong服务器地址:8000/代理path/原本的url
        StringBuffer buffer=new StringBuffer(kongNet);
        //就算route中的代理path有多个，这里也默认用它的第一个，后期可以改
        if(!paths.get(0).startsWith("/")){
            buffer.append("/");
        }
        buffer.append(paths.get(0));
        if(!controllerUrl.startsWith("/"))
            buffer.append("/");
        buffer.append(controllerUrl);
        return buffer.toString();
    }

    //从url中取出path和Controller层的接口地址
    public HashMap<String, String> getPath(String url){
        StringBuilder target = new StringBuilder("/");
        //这一步应该是为了解析出要代理的路由
        //解析出要代理的路由这个方法可以单独提出来，省的以后改找不到
        //目前应该是只考虑了http和https这两种协议
        //回指定字符在字符串中第一次出现处的索引，如果此字符串中没有这样的字符，则返回 -1
        int doubleIndex = url.indexOf("//");
        //public int indexOf(int ch, int fromIndex):
        // 返回从 fromIndex 位置开始查找指定字符在字符串中第一次出现处的索引，
        // 如果此字符串中没有这样的字符，则返回 -1
        int thirdIndex = url.indexOf("/", doubleIndex + 2);
        int fourthIndex = url.indexOf("/", thirdIndex + 1);
        /**http:www.example.com/hhhh 与 http://www.example.com/hhhh/worker 的区别*/
        fourthIndex = fourthIndex == -1 ? url.length() : fourthIndex;
        target.append(url, thirdIndex + 1, fourthIndex);
        StringBuilder controllerUrl=new StringBuilder("");
        controllerUrl.append(url,fourthIndex,url.length());
        HashMap<String,String> result=new HashMap<>();
        result.put("path",target.toString());
        result.put("controllerUrl",controllerUrl.toString());
        return result;
    }

    //route_path表主要为了保证path的唯一
    public void addRoutePaths(Route route) {
        List<String> pathList=route.getPaths();
        routePathsMapper.addPathList(pathList);
    }
}
